<template>
	<view class="chat-box" id="chat" :style="{ paddingBottom: isIphoneX ? (safeBottom + 70) + 'px': '70px' }" @longpress="handleLongPress"
	 @touchmove="handleTouchMove" @touchend="handleTouchEnd">
		<view :class="isRecording ? '' : 'modal-display'" class="record-modal">
			<view class="wrapper">
				<view class="modal-loading"></view>
			</view>
			<view class="modal-title">
				{{title}}
			</view>
		</view>
		<view class="chat-list" @click="loseFocus">
			<view class="item" v-for="(message, index) in currentMessageList" :key="index" :id="message.ID">
				<!--撤回的消息-->
				<view v-if="message.isRevoked" :key="message.ID">
					<view class="notice">
						<view class="content">
							<template v-if="message.from === myTimInfo.userID">你撤回了一条消息</template>
							<template v-else>{{message.from}}撤回了一条消息</template>
						</view>
						<template v-if="message.from === myTimInfo.userID">
							<view v-if="(currentTime - message.time < 120) && message.type === 'TIMTextElem'" @click="reEdit(message)" class="re-edit">重新编辑</view>
						</template>
					</view>
				</view>
				<!--非系统消息-->
				<view v-else :class="(message.flow === 'out') ? 'item-right' : 'item-left'">
					<view class="content">
						<view class="name">
							<template v-if="currentConversation.type === 'C2C'">
								<template v-if="message.flow === 'in'">
									{{currentConversation.userProfile.nick || currentConversation.userProfile.userID}}
								</template>
								<template v-else>
									{{myTimInfo.nick || myTimInfo.userID}}
								</template>
							</template>
							<template v-else>
								{{message.nameCard || message.nick || message.from}}
							</template>
						</view>
						<view class="wrapper" @longpress="handleMessage(message)">
							<view class="load" @click="handleResend(message)" v-if="message.from === myTimInfo.userID">
								<view :class="message.status">
								</view>
							</view>
							<view class="message" v-if="message.type === 'TIMTextElem'">
								<view class="text-message">
									<view v-for="(view, index2) in message.virtualDom" :key="index2">
										<text v-if="view.name === 'span'">{{view.text}}</text>
										<image v-if="view.name === 'img'" :src="view.src" style="width:20px;height:20px;" />
									</view>
								</view>
							</view>
							<image class="image-message" v-else-if="message.type === 'TIMImageElem'" :src="message.payload.imageInfoArray[1].url"
							 mode='widthFix' @click="previewImage(message.payload.imageInfoArray[1].url)" />
							<view class="message" v-else-if="message.type === 'TIMSoundElem'" :url="message.payload.url">
								<view class="box" @click="openAudio(message.payload)">
									<text class="iconfontPT iconsaying-copy"></text>
									<view style="padding-left: 4px;">{{message.payload.second}}s</view>
								</view>
							</view>
						</view>
					</view>
					<view>
						<!-- 自己发的消息头像 -->
						<image class="avatar" v-if="message.flow === 'out'" :src="myTimInfo.avatar" />
						<!-- 收到的消息头像 -->
						<image class="avatar" v-else-if="currentConversation.type === 'C2C'" @click="toDetail" :src="currentConversation.userProfile.avatar" />
						<image class="avatar" v-else @click="toDetail({ userID: message.from })" :src="message.avatar" />
					</view>
				</view>
			</view>
		</view>
		<!--输入框及选择框部分-->
		<view class="bottom" :style="{ paddingBottom: isIphoneX ? safeBottom + 'px': '' }">
			<view class="bottom-div" :style="{marginBottom: isFocus ? '10px' : 0}">
				<view class="btn-left" @click="chooseRecord">
					<text :class="{'iconfontPT': true, 'iconyuyin': isRecord, 'iconchakantiezimaikefeng': !isRecord}"></text>
				</view>
				<view v-if="!isRecord" style="width: 100%">
					<input type="text" class="input" v-model.lazy:value="messageContent" confirm-type="send" :focus="isFocus" @focus="isFocus = true"
					 @blur="isFocus = false" @confirm='sendMessage' />
				</view>
				<view class="record" id="record" v-if="isRecord">
					<template v-if="!isRecording">
						按住 说话
					</template>
					<template v-if="isRecording">
						抬起 停止
					</template>
				</view>

				<view class="btn" @click="handleEmoji()">
					<text class="iconfontPT iconxiaolian"></text>
				</view>
				<view class="send" @click="sendMessage" v-if="messageContent.length !== 0">
					发送
				</view>
				<view class="btn" @click="handleMore()" v-else>
					<text class="iconfontPT iconadd"></text>
				</view>
			</view>
			<!--emoji部分-->
			<view class="bottom-emoji" v-if="isEmojiOpen">
				<view class="emojis">
					<view v-for="(emojiItem, index3) in emojiName" class="emoji" :key="index3" @click="chooseEmoji(emojiItem)">
						<image :src="emojiUrl + emojiMap[emojiItem]" style="width:100%;height:100%" />
					</view>
				</view>
			</view>
			<!--更多部分-->
			<view class="bottom-image" v-if="isMoreOpen">
				<view class="images">
					<view class="block" @click="sendPhoto('camera')">
						<view class="image">
							<text class="iconfontPT iconpaizhaoshangchuan"></text>
						</view>
						<view class="name">
							拍摄
						</view>
					</view>
					<view class="block" @click="sendPhoto('album')">
						<view class="image">
							<text class="iconfontPT icontupian01"></text>
						</view>
						<view class="name">
							图片
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
 	import {
		emojiName,
		emojiMap,
		emojiUrl
	} from '../../../utils/emoji-map'

	import {
		optionsId,
		recordOptions
	} from '../../../setting.js'
	import {
		mapGetters
	} from "vuex";
	
	// let $tim = '';
	const audioContext = uni.createInnerAudioContext(),
		recorderManager = uni.getRecorderManager()

	export default {
		data() {
			return {
				messageContent: '',
				conversation: {},
				messageKey: '',
				lastMsgTime: '',
				count: 15,
				isEmojiOpen: false,
				isMoreOpen: false,
				isFocus: false,
				isGroup: false,
				messageList: [],
				emojiName: emojiName,
				emojiMap: emojiMap,
				emojiUrl: emojiUrl,
				height: 0,
				downloadInfo: {},
				safeBottom: 34,
				isRecord: false,
				isRecording: false,
				canSend: true,
				startPoint: 0,
				title: '正在录音',
				isShow: false,
				revokeModal: false,
				revokeMessage: {},
				currentTime: 0,
				currentTimeID: ''
			}
		},
		onShow() {
			this.isShow = true
			const that = this
			this.currentTimeID = setInterval(function() {
				that.currentTime = new Date().getTime() / 1000
			}, 3000)
		},
		onLoad(options) {
			this.set = options.toAccount
			// 设置header——聊天对象昵称或群名
			uni.setNavigationBarTitle({
				title: this.set
			})

			let query = uni.createSelectorQuery()
			let that = this
			uni.$Tim.on(this.TIM.EVENT.MESSAGE_RECEIVED, () => {
				query.select('#chat').boundingClientRect(function(res) {
					if (res.bottom - that.height < 150) {
						that.scrollToBottom()
					}
				}).exec()
			})
			let interval = setInterval(() => {
				if (this.currentMessageList.length !== 0) {
					this.scrollToBottom()
					clearInterval(interval)
				}
			}, 600)

			recorderManager.onStart(() => {
				console.log('recorder start')
			})
			recorderManager.onPause(() => {
				console.log('recorder pause')
			})
			recorderManager.onStop((res) => {
				console.log('recorder stop')
				let _this = this
				uni.hideLoading()
				if (_this.canSend) {
					if (res.duration < 1000) {
						_this.$store.commit('tim/SHOW_TOAST', {
							title: '录音时间太短'
						})
					} else {
						const message = uni.$Tim.createAudioMessage({
							to: _this.toAccount,
							conversationType: _this.currentConversationType,
							payload: {
								file: res
							}
						})
						_this.$store.commit('tim/SEND_MESSAGE', message)
						uni.$Tim.sendMessage(message)
					}
				}
			})
		},
		// 退出聊天页面的时候所有状态清空
		onUnload() {
			clearInterval(this.currentTimeID)
			uni.$Tim.setMessageRead({
				conversationID: this.currentConversationID
			})
			this.isEmojiOpen = false
			// this.rateModal = false
			this.isMoreOpen = false
			this.messageContent = ''
			this.isShow = false
			// eslint-disable-next-line
			const pages = getCurrentPages()
			// 若是由群组会话跳转到C2C会话，则在C2C会话 unload （返回上一层页面） 时，跳转到index页
			// 原因：若直接从C2C会话返回群组会话，由于此时currentConversation和currentMessageList已变更，会导致数据不一致的问题，简单起见，直接跳回index
			const hasGroupChat = pages.find(item => item.options.type === this.TIM.TYPES.CONV_GROUP)
			if (hasGroupChat) {
				uni.switchTab({
					url: '../index/main'
				})
			}
		},
		onPullDownRefresh() {
			this.$throttle(this.getMessageList, 1000)
		},
		computed: {
			...mapGetters(['isIphoneX', 'currentMessageList', 'currentConversation', 'myTimInfo', 'toAccount',
				'currentConversationType', 'currentConversationID'
			])
		},
		methods: {
			// 长按录音，监听在页面最外层view，如果是放在button的话，手指上划离开button后获取距离变化有bug
			handleLongPress(e) {
				this.startPoint = e.touches[0]
				if (e.target.id === 'record') {
					this.title = '正在录音'
					this.isRecording = true
					this.startRecording()
					this.canSend = true
				}
			},
			chooseRecord() {
				this.isRecord = !this.isRecord
			},
			// 录音时的手势上划移动距离对应文案变化
			handleTouchMove(e) {
				if (this.isRecording) {
					if (this.startPoint.clientY - e.touches[e.touches.length - 1].clientY > 100) {
						this.title = '松开手指，取消发送'
						this.canSend = false
					} else if (this.startPoint.clientY - e.touches[e.touches.length - 1].clientY > 20) {
						this.title = '上划可取消'
						this.canSend = true
					} else {
						this.title = '正在录音'
						this.canSend = true
					}
				}
			},
			// 手指离开页面滑动
			handleTouchEnd() {
				this.isRecording = false
				uni.hideLoading()
				recorderManager.stop()
			},
			// 开始录音之前要判断一下是否开启权限
			startRecording() {
				uni.getSetting({
					success: (res) => {
						let auth = res.authSetting['scope.record']
						if (auth === false) { // 已申请过授权，但是用户拒绝
							uni.openSetting({
								success: function(res) {
									let auth = res.authSetting['scope.record']
									if (auth === true) {
										uni.showToast({
											title: '授权成功',
											icon: 'success',
											duration: 1500
										})
									} else {
										uni.showToast({
											title: '授权失败',
											icon: 'none',
											duration: 1500
										})
									}
								}
							})
						} else if (auth === true) { // 用户已经同意授权
							this.isRecording = true
							recorderManager.start(recordOptions)
						} else { // 第一次进来，未发起授权
							uni.authorize({
								scope: 'scope.record',
								success: () => {
									uni.showToast({
										title: '授权成功',
										icon: 'success',
										duration: 1500
									})
								}
							})
						}
					},
					fail: function() {
						uni.showToast({
							title: '授权失败',
							icon: 'none',
							duration: 1500
						})
					}
				})
			},
			// 滚动到列表bottom
			scrollToBottom() {
				if (this.isShow) {
					uni.pageScrollTo({
						scrollTop: 99999
					})
				}
			},
			// 失去焦点
			loseFocus() {
				this.handleClose()
			},
			// 获取消息
			getMessageList() {
				this.$store.dispatch('tim/getMessageList')
				uni.stopPullDownRefresh()
			},
			// 处理emoji选项卡
			handleEmoji() {
				if (this.isFocus) {
					this.isFocus = false
					this.isEmojiOpen = true
				} else {
					this.isEmojiOpen = !this.isEmojiOpen
					this.isMoreOpen = false
				}
			},
			// 处理更多选项卡
			handleMore() {
				if (this.isFocus) {
					this.isFocus = false
					this.isMoreOpen = true
				} else {
					this.isMoreOpen = !this.isMoreOpen
					this.isEmojiOpen = false
				}
			},
			// 选项卡关闭
			handleClose() {
				// this.rateModal = false
				this.isFocus = false
				this.isMoreOpen = false
				this.isEmojiOpen = false
			},
			isnull(content) {
				if (content === '') {
					return true
				}
				const reg = '^[ ]+$'
				const re = new RegExp(reg)
				return re.test(content)
			},
			// 发送text message 包含 emoji
			sendMessage() {
				let _this = this
				if (!this.isnull(this.messageContent)) {
					const message = uni.$Tim.createTextMessage({
						to: _this.toAccount,
						conversationType: _this.currentConversationType,
						payload: {
							text: _this.messageContent
						}
					})
					let index = this.currentMessageList.length
					this.$store.commit('tim/SEND_MESSAGE', message)
					uni.$Tim.sendMessage(message).catch(() => {
						_this.$store.commit('tim/changeMessageStatus', index)
					})
					this.messageContent = ''
				} else {
					this.$store.commit('tim/SEND_MESSAGE', {
						title: '消息不能为空'
					})
				}
				this.isFocus = false
				this.isEmojiOpen = false
				this.isMoreOpen = false
			},
			sendPhoto(name) {
				let self = this
				if (name === 'album') {
					this.chooseImage(name)
				} else if (name === 'camera') {
					uni.getSetting({
						success: function(res) {
							if (!res.authSetting['scope.camera']) { // 无权限，跳转设置权限页面
								uni.authorize({
									scope: 'scope.camera',
									success: function() {
										self.chooseImage(name)
									}
								})
							} else {
								self.chooseImage(name)
							}
						}
					})
				}
			},
			chooseImage(name) {
				let _this = this
				let message = {}
				uni.chooseImage({
					sourceType: [name],
					count: 1,
					success: function(res) {
						message = uni.$Tim.createImageMessage({
							to: _this.toAccount,
							conversationType: _this.currentConversationType,
							payload: {
								file: res
							},
							onProgress: percent => {
								_this.percent = percent
							}
						})
						_this.$store.commit('tim/SEND_MESSAGE', message)
						uni.$Tim.sendMessage(message).then(() => {
							_this.percent = 0
						}).catch((err) => {
							console.log(err)
						})
					}
				})
				this.handleClose()
			},
			previewImage(src) {
				uni.previewImage({
					current: src, // 当前显示图片的http链接
					urls: [src]
				})
			},
			// 发消息选中emoji
			chooseEmoji(item) {
				this.messageContent += item
			},
			// 重发消息
			handleResend(message) {
				if (message.status === 'fail') {
					uni.$Tim.resendMessage(message)
				}
			},
			// 播放音频
			openAudio(audio) {
				let that = this
				audioContext.src = audio.url
				audioContext.play()
				audioContext.onPlay(() => {})
				audioContext.onEnded(() => {
					uni.hideToast()
				})
				audioContext.onError(() => {
					that.$store.commit('tim/SHOW_TOAST', {
						title: '小程序暂不支持播放该音频格式',
						icon: 'none',
						duration: 2000
					})
				})
			},
			getRandomInt(min, max) {
				min = Math.ceil(min)
				max = Math.floor(max)
				return Math.floor(Math.random() * (max - min)) + min
			},
			// 长按消息触发是否撤回
			handleMessage(message) {
				if (message.from === this.myTimInfo.userID) {
					const revokeTimeout = 2 * 60 * 1000
					const now = new Date().getTime()
					if (now - message.time * 1000 < revokeTimeout) {
						this.revokeModal = true
						this.revokeMessage = message
					}
				}
			},
			// 撤回消息
			handleRevokeMessage() {
				uni.$Tim.revokeMessage(this.revokeMessage).then(res => {
					console.log(res)
					this.revokeModal = false
					this.$store.commit('tim/SHOW_TOAST', {
						title: '撤回成功',
						duration: 500
					})
				})
			},
			// 撤回后时间限制内，重新编辑
			reEdit(message) {
				this.messageContent = message.payload.text
			}
		},
	}
</script>

<style lang="less">
	.loadMore {
		font-size: 28rpx;
		color: #8a8a8a;
		box-sizing: border-box;
		width: 100%;
		padding: 30rpx;
		display: flex;
		justify-content: center;
	}

	.iconfontPT {
		font-size: 50rpx;
	}

	.unload {
		font-size: 0;
		color: #fff;
		box-sizing: border-box;
		width: 100%;
		text-align: center;
	}

	.emoji-open {
		height: calc(100vh - 524rpx);
	}

	.emoji-close {
		height: calc(100vh - 164rpx);
	}

	.chat-box {
		background-color: #fff;
		box-sizing: border-box;

		.chat-list {
			.item {
				margin-top: 36rpx;
				padding: 0 24rpx;
			}
		}
	}

	.file {
		display: flex;
		text-align: left;
		width: fit-content;
		word-break: break-all;
		font-size: 28rpx;
		background-color: #fff;
		padding: 20rpx 16rpx;
	}

	.bottom {
		background-color: #ededed;
		position: fixed;
		bottom: 0;
		left: 0;
		width: 100%;
	}

	.bottom-div {
		width: 100%;
		display: flex;
		align-items: center;
		border-top: 2rpx solid #ddd;
		padding: 20rpx;
		flex-direction: row;
		box-sizing: border-box;
		transition: all 0.3s;
	}

	.bottom-div .send {
		font-size: 28rpx;
		background-color: #006fff;
		color: #fff;
		border-radius: 8rpx;
		width: 100rpx;
		height: fit-content;
		padding: 12rpx;
		margin-left: 12rpx;
		text-align: center;
	}

	.bottom-emoji {
		position: relative;
	}

	.bottom-emoji .emojis {
		height: 300rpx;
		display: flex;
		flex-direction: row;
		flex-wrap: wrap;
		overflow-y: scroll;
		box-sizing: border-box;
	}

	.bottom-emoji .emojis .emoji {
		height: 12.5vw;
		width: 12.5vw;
		padding: 16rpx;
		box-sizing: border-box;
	}

	.bottom-image {
		box-sizing: border-box;
	}

	.bottom-image .images {
		box-sizing: border-box;
		display: flex;
		padding: 0 24rpx;
		margin-top: 32rpx;
	}

	.bottom-image .images:last-child {
		margin-bottom: 32rpx;
	}

	.bottom-image .images .block {
		box-sizing: border-box;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
		margin: 0 24rpx;
	}

	.bottom-image .images .block .name {
		margin-top: 12rpx;
		font-size: 24rpx;
		color: #999;
		text-align: center;
	}

	.bottom-image .images .block .image {
		width: 128rpx;
		height: 128rpx;
		display: flex;
		justify-content: center;
		align-items: center;
		box-sizing: border-box;
		border-radius: 16rpx;
		background-color: #fff;
		padding: 3vw;
	}

	// .bottom-image .images .block .image .icon {
	// 	width: 52rpx;
	// 	height: 52rpx;
	// }

	.input {
		background-color: #fff;
		border-radius: 12rpx;
		height: 68rpx;
		box-sizing: border-box;
		padding: 0 16rpx;
	}

	.btn-left {
		display: flex;
		padding: 0;
		margin: 0;
		margin-right: 20rpx;
	}

	.btn {
		display: flex;
		padding: 0;
		margin: 0;
		margin-left: 20rpx;
	}

	.button {
		color: #fff;
		background-color: #006fff;
		border-radius: 16rpx;
		height: 52rpx;
		padding: 0 12rpx;
		line-height: 52rpx;
		font-size: 32rpx;
	}

	.input-wrapper {
		width: 100%;
		display: flex;
		justify-content: center;
	}

	._li {
		margin-top: 36rpx;
		padding: 0 24rpx;
	}

	.fail::before {
		padding: 4rpx 16rpx;
		background-color: #fb5250;
		color: #fff;
		content: '!';
		font-size: 24rpx;
		border-radius: 50%;
		cursor: pointer;
	}

	@-webkit-keyframes load {
		from {
			transform: rotate(0deg);
		}

		to {
			transform: rotate(360deg);
		}
	}

	.notice {
		display: flex;
		justify-content: center;
		margin-bottom: 20rpx;
	}

	.notice .content {
		background-color: #ededed;
		border-radius: 16rpx;
		font-size: 28rpx;
		color: #495060;
		padding: 12rpx 16rpx;
	}

	.message {
		font-size: 32rpx;
		line-height: 44rpx;
		text-align: left;
		width: fit-content;
		word-break: break-all;
		background-color: #c4c4c4;
		padding: 24rpx;
	}

	.text-message {
		display: flex;
		flex-direction: row;
		flex-wrap: wrap;
		white-space: pre-wrap;
	}

	.image-message {
		max-width: 360rpx;
		border-radius: 4rpx;
	}

	.fail {
		background-color: transparent;
	}

	.unSend {
		width: 24rpx;
		height: 24rpx;
		border: 8rpx solid #98c6fd;
		border-bottom: #dbdbdb 8rpx solid;
		border-radius: 50%;
		-webkit-animation: load 1.1s infinite linear;
	}

	.item-right {
		display: flex;
		flex-direction: row;
		justify-content: flex-end;
		height: 100%;
	}

	.item-right .load {
		height: 100%;
		width: 60rpx;
		display: flex;
		flex-direction: column;
		justify-content: center;
	}

	.item-right .content {
		margin-right: 24rpx;
		display: flex;
		flex-direction: column;
		align-items: flex-end;
	}

	.item-right .content .name {
		width: 100%;
		font-size: 24rpx;
		line-height: 1;
		margin-bottom: 12rpx;
		color: #999;
		text-align: right;
	}

	.item-right .content .wrapper {
		display: flex;
		flex-direction: row;
		height: 100%;
	}

	.item-right .content .wrapper .message {
		background-color: rgba(0, 111, 255, 0.1);
		border: 2rpx solid rgba(0, 111, 255, 0.3);
		border-radius: 16rpx 4rpx 16rpx 16rpx;
	}

	.item-left {
		display: flex;
		flex-direction: row-reverse;
		justify-content: flex-end;
	}

	.item-left .content {
		margin-left: 20rpx;
	}

	.item-left .content .name {
		width: 100%;
		font-size: 24rpx;
		line-height: 1;
		color: #999;
		margin-bottom: 12rpx;
	}

	.item-left .content .message {
		background-color: #f8f8f8;
		border: 2rpx solid #f1f1f1;
		border-radius: 4rpx 16rpx 16rpx 16rpx;
	}

	.box {
		display: flex;
		height: 40rpx;
		line-height: 40rpx;
	}

	.record {
		width: 100%;
		background-color: #fff;
		color: #495060;
		border-radius: 12rpx;
		box-sizing: border-box;
		height: 68rpx;
		line-height: 68rpx;
		display: flex;
		justify-content: center;
	}

	.record-modal {
		height: 300rpx;
		width: 60vw;
		background-color: #000;
		opacity: 0.8;
		position: fixed;
		top: 400rpx;
		z-index: 9999;
		left: 20vw;
		border-radius: 24rpx;
		display: flex;
		flex-direction: column;
	}

	.record-modal .wrapper {
		display: flex;
		height: 200rpx;
		box-sizing: border-box;
		padding: 10vw;
	}

	.record-modal .wrapper .modal-loading {
		opacity: 1;
		width: 40rpx;
		height: 16rpx;
		border-radius: 4rpx;
		background-color: #006fff;
		animation: loading 2s cubic-bezier(0.17, 0.37, 0.43, 0.67) infinite;
	}

	.record-modal .modal-title {
		text-align: center;
		color: #fff;
	}

	@-webkit-keyframes loading {
		0% {
			transform: translate(0, 0);
		}

		50% {
			transform: translate(30vw, 0);
			background-color: #f5634a;
			width: 80rpx;
		}

		100% {
			transform: translate(0, 0);
		}
	}

	.modal-display {
		display: none;
	}

	.avatar {
		height: 80rpx !important;
		width: 80rpx !important;
		border-radius: 8rpx !important;
	}

	.re-edit {
		color: #006fff;
		line-height: 60rpx;
		font-size: 28rpx;
		margin-left: 20rpx;
	}
</style>
